﻿using System;
using System.Collections.Generic;
using System.Linq;

using zijian666.Core.Abstractions;

namespace zijian666.Core;

/// <summary>
/// 功能描述
/// </summary>
internal sealed class FeatureDescription : IOrdered
{
    public FeatureDescription(object instance)
    {
        Feature = instance ?? throw new ArgumentNullException(nameof(instance));

        Order = (instance as IOrdered)?.Order ?? 0;
        FeatureType = instance.GetType();
        var slotSetters = new List<ISlotSetter>();
        foreach (var item in instance.GetType().GetInterfaces())
        {
            if (item.Name == "IMultiSlot`1" && item.GetGenericTypeDefinition() == typeof(IMultiSlot<>))
            {
                slotSetters.Add((ISlotSetter)Activator.CreateInstance(typeof(SlotSetter<>).MakeGenericType(item.GetGenericArguments())));
            }
            else if (item.Name == "ISlot`1" && item.GetGenericTypeDefinition() == typeof(ISlot<>))
            {
                slotSetters.Add((ISlotSetter)Activator.CreateInstance(typeof(SlotSetter<>).MakeGenericType(item.GetGenericArguments())));
            }
        }
        _slotSetters = slotSetters.Distinct().ToList();

        AutoRefreshSlot = instance is IAutoRefreshSlot || _slotSetters.Any(x => x.AutoRefreshSlot(instance));
    }

    public int Order { get; }

    /// <summary>
    /// 功能组件
    /// </summary>
    public object Feature { get; }

    /// <summary>
    /// 功能组件类型
    /// </summary>
    public Type FeatureType { get; }

    /// <summary>
    /// 新增删除注册新组件是否自动刷新插槽
    /// </summary>
    public bool AutoRefreshSlot { get; }

    private readonly List<ISlotSetter> _slotSetters;

    /// <summary>
    /// 刷新插槽
    /// </summary>
    public void RefreshSlot()
    {
        foreach (var setter in _slotSetters)
        {
            setter.Set(Feature);
        }
    }

    public void RefreshSlot(bool force)
    {
        if (force || Feature is IAutoRefreshSlot)
        {
            RefreshSlot();
            return;
        }
        foreach (var setter in _slotSetters)
        {
            if (setter.AutoRefreshSlot(Feature))
            {
                setter.Set(Feature);
            }
        }
    }


    public bool IsInstanceOf(Type type) => type?.IsInstanceOfType(Feature) ?? false;

    public bool IsInstanceOf<T>() => Feature is T;


    public override bool Equals(object obj) => obj is FeatureDescription description && Equals(Feature, description.Feature);

    public override int GetHashCode() => Feature.GetHashCode();

    public override string ToString() => "FeatureDescription:" + Feature.ToString();

    interface ISlotSetter
    {
        void Set(object instanc);
        bool AutoRefreshSlot(object instance);
    }

    class SlotSetter<T> : ISlotSetter
        where T : class
    {
        void ISlotSetter.Set(object instance)
        {
            if (instance is IMultiSlot<T> mslot)
            {
                var features = FeatureManager.Gets<T>();
                mslot.MultiSet(features);
            }
            else if (instance is ISlot<T> slot)
            {
                var features = FeatureManager.Gets<T>();
                foreach (var feature in features)
                {
                    slot.Set(feature);
                }
            }
        }
        public override bool Equals(object obj) => obj is SlotSetter<T>;

        public override int GetHashCode() => typeof(T).GetHashCode();

        public override string ToString() => base.ToString();

        public bool AutoRefreshSlot(object instance) => instance is IAutoRefreshMultiSlot<T> || instance is IAutoRefreshSlot<T>;
    }
}
